package samsung.entities;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import samsung.other.Position;

/**
 * Class describe city entity, realized methods needed for coins dissemination
 * between neighbors.
 *
 * @author Vitaliy Muzalevskiy
 */
public class City {
    
    public static final int START_CAPITAL = 1000000;
    public static final int TRANSPORTING_PORTION_DETECTOR = 1000;
    private String nativeCountryName;
    private final Position position;
    private boolean finish;
    private Map<String, Integer> coins = new HashMap<String, Integer>();
    private List<City> neighbors = new ArrayList<City>();
    
    public City(Position position, String nativeCountryName){
        this.position = position;
        this.nativeCountryName = nativeCountryName;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + Objects.hashCode(this.position);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final City other = (City) obj;
        if (!Objects.equals(this.position, other.position)) {
            return false;
        }
        return true;
    }

    public Position getPosition() {
        return position;
    }

    public boolean isFinish() {
        return finish;
    }
    
    /**
     * Method check if current city already end dissemination of all types
     * of coins, and set finish marker if it does.
     *
     * @return <code>true</code> if city already have all types of coins.
     */
    public boolean finishDissemination() {
        for(Integer value: coins.values()){
            if (value == 0){
                return false;
            }
        }
        finish = true;
        return true;
    }

    public String getNativeCountryName() {
        return nativeCountryName;
    }
    
    /**
     * Add new coin type from another country of current area to coins type list.
     *
     * @param countryName - name of a country where this coins were made.
     */
    public void addCoinsType(String countryName){
        coins.put(countryName, 0);
    }
    
    /**
     * Method return quantity of coins of defined country.
     *
     * @param countryName - name of a country where this coins were made.
     * @return - quantity of coins of defined country. 
     */
    public int getCoinsValueByType(String countryName){
        return coins.get(countryName);
    }
    
    /**
     * Method add defined start quantity of coins of native country as a start
     * capital of current city.
     *
     */
    public void addStartCapital(){
        coins.put(nativeCountryName, START_CAPITAL);
    }

    @Override
    public String toString() {
        return "City{" + "position=" + position + '}';
    }
       
    /**
     * Method realized action of coins dissemination between neighbors.
     */
    public void giveMoney(){
        Map<String, Integer> transportedMoney = getTransportedMoneyValues();
        for(City city: neighbors){
            for(String countryName: transportedMoney.keySet()){
                int value = transportedMoney.get(countryName);
                city.receiveMoney(countryName, value);
                coins.put(countryName, getCoinsValueByType(countryName) - value);
            }
        }
    }
    
    private void receiveMoney(String countryName, int value){      
        coins.put(countryName, getCoinsValueByType(countryName) + value);
    }
    
    private Map<String, Integer> getTransportedMoneyValues(){
        Map<String, Integer> result = new HashMap<String, Integer>();
        for(String countryName: coins.keySet()){
            int value = getCoinsValueByType(countryName)/TRANSPORTING_PORTION_DETECTOR;
            if(value > 0){
                result.put(countryName, value);
            }
        }
        return result;
    }
    
    /**
     * Method add new neighbor city to a neighbor list.
     *
     * @param city - <code>City</code> object that is a neighbor of current 
     *      city.
     */
    public void addNeighbor(City city){
        neighbors.add(city);
    }
    
    public List<City> getNeighbors(){
        List<City> result = new ArrayList<City>(neighbors);
        return result;
    }
}
